package com.chiyoyo.shiro.framework;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;

import javax.annotation.PostConstruct;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Shiro 安全配置类，负责初始化 Shiro 的核心组件（如 Realm、SecurityManager 和 Filter）并配置权限拦截规则。
 * 1. 配置自定义 Realm（MyRealm）进行用户认证和授权
 * 2. 配置 SecurityManager 并绑定 Realm
 * 3. 配置 ShiroFilterFactoryBean 实现 URL 权限拦截
 * 4. 集成自定义的 MyAccessControlFilter 处理登录验证
 *
 * @author chil
 * @since 2024/8/6
 */
@Slf4j
@EnableConfigurationProperties(ShiroProperties.class) // 注入 ShiroProperties 配置属性
public class ShiroConfig {

    /**
     * 创建自定义 Realm 对象（MyRealm），用于用户身份认证和权限验证
     *
     * @return MyRealm 实例
     */
    @Bean
    @ConditionalOnMissingBean // 确保仅创建一次 Bean
    public MyRealm myRealm() {
        return new MyRealm();
    }

    /**
     * 创建 Shiro 的 SecurityManager 实例，并绑定自定义 Realm
     *
     * @param myRealm 自定义 Realm 对象
     * @return DefaultWebSecurityManager 实例
     */
    @Bean
    @ConditionalOnMissingBean
    public DefaultWebSecurityManager defaultWebSecurityManager(MyRealm myRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm); // 关联 Realm 进行权限验证
        return securityManager;
    }

    /**
     * 配置 Shiro 过滤器链，定义 URL 权限拦截规则和自定义过滤器
     *
     * @param defaultWebSecurityManager 安全管理器实例
     * @param shiroProperties           Shiro 配置属性（如白名单）
     * @return ShiroFilterFactoryBean 实例
     */
    @Bean
    @DependsOn("defaultWebSecurityManager") // 依赖 SecurityManager 初始化完成后再执行
    @ConditionalOnMissingBean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(
            DefaultWebSecurityManager defaultWebSecurityManager,
            ShiroProperties shiroProperties) {

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        // 配置拦截规则链
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        // 白名单配置：无需认证即可访问的 URL
        List<String> whiteList = shiroProperties.getWhiteList();
        if (whiteList != null) {
            log.info("白名单配置：{}", whiteList);
            whiteList.forEach(url -> filterChainDefinitionMap.put(url, "anon")); // anon 表示无需认证
        }

        // 全局配置：所有请求需通过 CORS 和自定义认证过滤器
        filterChainDefinitionMap.put("/**", "myAccessControlFilter");

        // 注册自定义过滤器（MyAccessControlFilter）
        Map<String, Filter> filters = new HashMap<>();
        filters.put("myAccessControlFilter", new MyAccessControlFilter());
        shiroFilterFactoryBean.setFilters(filters);

        // 设置未授权访问的跳转地址
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 将 SecurityManager 绑定到 Shiro 的全局上下文中，确保 Shiro 能正常工作
     */
    @PostConstruct // 在 Bean 初始化完成后执行
    public void bindSecurityManager() {
        SecurityUtils.setSecurityManager(defaultWebSecurityManager(myRealm()));
    }
}

